﻿using System;
using System.Collections.Generic;
using System.Text;
using SAServices.Model;
using SAServices.BLL;
using SAServices.DAL;
using System.IO;
using System.Drawing;
using System.Configuration;
using System.Web.Security;

namespace SAServices.Service
{
    public class ProgressEventArgs : EventArgs
    {
        public ProgressEventArgs(int s)
        {
            step = s;
        }
        private int step;
        public int Step
        {
            get { return step; }
        }
    }

    public class PubServiceMethod
    {
        public string lastErrMsg;

        private ConnectionConext m_curConnCtx;
        private static PubServiceMethod m_instance;

        private static string m_serverName;
        private static string m_userName;
        private static string m_password;

        public static bool ReSignIn(string server, string username, string password)
        {
            m_serverName = server;
            m_userName = username;
            m_password = password;

            m_instance = new PubServiceMethod();

            bool ret = m_instance.LogIn(m_serverName, m_userName, m_password);

            return ret;
        }

        public static PubServiceMethod Instance()
        {
            if (m_instance == null)
            {
                m_instance = new PubServiceMethod();
                if (!m_instance.LogIn(m_serverName, m_userName, m_password))
                    throw new Exception(m_instance.lastErrMsg);
            }

            if (!m_instance.IsConnected())
            {
                if (!m_instance.LogIn(m_serverName, m_userName, m_password))
                    throw new Exception(m_instance.lastErrMsg);
            }

            return m_instance;
        }

        #region LogIn/LogOut
        private bool IsConnected()
        {
            if (m_curConnCtx != null && m_curConnCtx.TestConnection())
            {
                return true;
            }
            return false;
        }

        private bool LogIn(string serverName, string useName, string password)
        {
            try
            {
                m_curConnCtx = new ConnectionConext(serverName, useName, password);
                if (!m_curConnCtx.TestConnection())
                {


                    lastErrMsg = @"无法建立连接！";
                    return false;
                }

                return true;

            }
            catch (System.Exception ex)
            {
                lastErrMsg = @"登录失败：" + ex.Message;
                return false;
            }
        }

        private void LogOut()
        {
            if (m_curConnCtx != null)
            {
                m_curConnCtx.Close();
            }
        }
        #endregion

        #region category methods.
        public List<CategoryInfo> GetRootCategories()
        {
            return CategoryBLL.GetRootCategories(m_curConnCtx);
        }

        public List<CategoryInfo> GetSubCategories(CategoryInfo parentCategory)
        {
            return CategoryBLL.GetSubCategories(m_curConnCtx, parentCategory);
        }

        public bool IsCategoryContainsFamilyFromVendor(CategoryInfo category, int vendorId, bool bIncludeSubCategory)
        {
            List<FamilyInfo> families = FamilyBLL.GetFamiliesByCategoryId(m_curConnCtx, category.Id);
            
            if(families != null && families.Count > 0)
            {

                for (int i = 0; i < families.Count; i++ )
                {
                    string catename = families[i].Name;
                    string cateid = families[i].CategoryID.ToString();
                    string cate = families[i].VendorID.ToString();
                    if (families[i].VendorID == vendorId)
                    {
                        

                        return true;
                    }
                }
            }

            if (bIncludeSubCategory)
            {
                List<CategoryInfo> cateList = GetSubCategories(category);

                foreach (CategoryInfo curCateInfo in cateList)
                {
                    bool bHasFamily = IsCategoryContainsFamilyFromVendor(curCateInfo, vendorId, bIncludeSubCategory);

                    if (bHasFamily)
                    {
                        return true;
                    }
                }
            }

            return false;

        }

        public bool AddCategory(CategoryInfo newCategoryInfo)
        {
            return CategoryBLL.AddCategory(m_curConnCtx, newCategoryInfo);
        }

        public bool DeleteCategory(Guid cateId)
        {
            return CategoryBLL.DeleteCategory(m_curConnCtx, cateId);
        }

        public bool UpdateCategory(CategoryInfo updateCategoryInfo)
        {
            return CategoryBLL.UpdateCategory(m_curConnCtx, updateCategoryInfo);
        }

        public CategoryInfo GetCategoryInfoByCateId(Guid cateId)
        {
            return CategoryBLL.GetCategoryInfoByCateId(m_curConnCtx, cateId);
        }
        #endregion

        #region standard methods.

        public bool AddStandard(StandardInfo newStandardInfo)
        {
            return StandardBLL.AddStandard(m_curConnCtx, newStandardInfo);
        }

        public bool UpdateStandard(StandardInfo updateStandardInfo)
        {
            return StandardBLL.UpdateStandard(m_curConnCtx, updateStandardInfo);
        }

        public bool DeleteStandard(string standardName)
        {
            return StandardBLL.DeleteStandard(m_curConnCtx, standardName);
        }

        public StandardInfo GetStandard(string standardName)
        {
            return StandardBLL.GetStandard(m_curConnCtx, standardName);
        }

        public StandardInfo GetStandard(int standardId)
        {
            return StandardBLL.GetStandard(m_curConnCtx, standardId);
        }

        public List<StandardInfo> GetAllStandards()
        {
            return StandardBLL.GetAllStandards(m_curConnCtx);
        }

        #endregion

        #region ventor methods.

        public bool AddVendor(VendorInfo newVendorInfo)
        {
            return VendorBLL.AddVendor(m_curConnCtx, newVendorInfo);
        }

        public bool UpdateVendor(VendorInfo updateVendorInfo)
        {
            return VendorBLL.UpdateVendor(m_curConnCtx, updateVendorInfo);
        }

        public bool DeleteVendor(string vendorName)
        {
            return VendorBLL.DeleteVendor(m_curConnCtx, vendorName);
        }

        public VendorInfo GetVendor(string vendorName)
        {
            return VendorBLL.GetVendor(m_curConnCtx, vendorName);
        }

        public VendorInfo GetVendor(int vendorId)
        {
            return VendorBLL.GetVendor(m_curConnCtx, vendorId);
        }

        public List<VendorInfo> GetAllVendors()
        {
            return VendorBLL.GetAllVendors(m_curConnCtx);
        }

        #endregion

        public bool PublishFamily(FamilyInfo familyInfo, FamilyAttrInfo familyAttrInfo, FamilyTableInfo familyTableInfo)
        {
            bool bSuccess = true;
            try
            {
                //add family info.
                bSuccess = FamilyBLL.AddFamilyInfo(m_curConnCtx, familyInfo);

                //add familyAttrInfo
                bSuccess = FamilyAttrBLL.AddFamilyAttrInfo(m_curConnCtx, familyAttrInfo);

                //add family parameters.
                bSuccess = ParameterBLL.AddFamilyParameters(m_curConnCtx, familyTableInfo.Parameters);

                //add familyTableInfo
                bSuccess = FamilyTableBLL.AddFamilyTableInfo(m_curConnCtx, familyTableInfo);
            }
            catch (System.Exception ex)
            {
                Guid familyId = familyInfo.ID;

                //add family info.
                bSuccess = FamilyBLL.DeleteFamilyInfo(m_curConnCtx, familyId);

                //add familyAttrInfo
                bSuccess = FamilyAttrBLL.DeleteFamilyAttrInfo(m_curConnCtx, familyId);

                //delete family parameters.
                bSuccess = ParameterBLL.DeleteFamilyParameters(m_curConnCtx, familyId);

                //add familyTableInfo
                bSuccess = FamilyTableBLL.DeleteFamilyTableInfo(m_curConnCtx, familyId);

                throw new Exception(ex.Message);
            }

            return true;
        }

        public bool UpdateFamily(FamilyInfo familyInfo, FamilyAttrInfo familyAttrInfo, FamilyTableInfo familyTableInfo)
        {
            bool bSuccess = true;
            try
            {
                //add family info.
                bSuccess = FamilyBLL.UpdateFamilyInfo(m_curConnCtx, familyInfo);

                //add familyAttrInfo
                bSuccess = FamilyAttrBLL.UpdateFamilyAttrInfo(m_curConnCtx, familyAttrInfo);

                //add family parameters.
                bSuccess = ParameterBLL.UpdateFamilyParameters(m_curConnCtx, familyTableInfo.Parameters);

                //add familyTableInfo
                bSuccess = FamilyTableBLL.UpdateFamilyTableInfo(m_curConnCtx, familyTableInfo);
            }
            catch (System.Exception ex)
            {
                Guid familyId = familyInfo.ID;

                //add family info.
                //bSuccess = FamilyBLL.DeleteFamilyInfo(m_curConnCtx, familyId);

                //add familyAttrInfo
                //bSuccess = FamilyAttrBLL.DeleteFamilyAttrInfo(m_curConnCtx, familyId);

                //delete family parameters.
                //bSuccess = ParameterBLL.DeleteFamilyParameters(m_curConnCtx, familyId);

                //add familyTableInfo
                //bSuccess = FamilyTableBLL.DeleteFamilyTableInfo(m_curConnCtx, familyId);

                throw new Exception(ex.Message);
            }

            return true;
        }

        public bool DeleteFamily(Guid familyId)
        {
            bool bSuccess = true;
            try
            {
                //add family info.
                bSuccess = FamilyBLL.DeleteFamilyInfo(m_curConnCtx, familyId);

                //add familyAttrInfo
                bSuccess = FamilyAttrBLL.DeleteFamilyAttrInfo(m_curConnCtx, familyId);

                //delete family parameters.
                bSuccess = ParameterBLL.DeleteFamilyParameters(m_curConnCtx, familyId);

                //add familyTableInfo
                bSuccess = FamilyTableBLL.DeleteFamilyTableInfo(m_curConnCtx, familyId);

            }
            catch (System.Exception ex)
            {
                //pre process.

                throw new Exception(ex.Message);
            }

            return true;
        }

        public FamilyAttrInfo GetFamilyAttrInfo(Guid familyId, FamilyAttrType type)
        {
            return FamilyAttrBLL.GetFamilyAttrInfo(m_curConnCtx, familyId, type); 
        }

        public FamilyAttrInfo GetFamilyAttrInfo(Guid familyId)
        {
            return FamilyAttrBLL.GetFamilyAttrInfo(m_curConnCtx, familyId);
        }

        public byte[] GetFamilyThumbnailPic(Guid familyId)
        {
            return FamilyAttrBLL.GetFamilyThumbnailPic(m_curConnCtx, familyId);
        }

        public List<FamilyInfo> GetFamiliesByCategoryId(Guid cateId)
        {
            return FamilyBLL.GetFamiliesByCategoryId(m_curConnCtx, cateId);
        }
        public List<FamilyInfo> GetFamiliesByCategoryIdnew(Guid cateId, string str, string searchString)
        {
            return FamilyBLL.GetFamiliesByCategoryIdnew(m_curConnCtx, cateId, str, searchString);
        }

        public FamilyInfo GetFamilyInfo(Guid famiId)
        {
            return FamilyBLL.GetFamilyInfo(m_curConnCtx, famiId);
        }

        public List<FamilyInfo> GetFamilyInfoNew()
        {
            return FamilyBLL.GetFamilyInfoNew(m_curConnCtx);
        }

        public List<FamilyInfo> GetFamiliesByVendorId(int vendorId, string searchString)
        {
            return FamilyBLL.GetFamiliesByVendorId(m_curConnCtx, vendorId, searchString);
        }

        public List<FamilyInfo> GetFamiliesByStandardId(int standardId)
        {
            return FamilyBLL.GetFamiliesByStandardId(m_curConnCtx, standardId);
        }

        public List<FamilyInfo> GetFamiliesByCategoryVendorId(Guid cateId, int vendorId, string searchString,string str)
        {
            return FamilyBLL.GetFamiliesByCategoryVendorId(m_curConnCtx, cateId, vendorId, searchString,str);
        }

        public List<FamilyInfo> SearchFamilies(string searchString)
        {
            return FamilyBLL.SearchFamilies(m_curConnCtx, searchString);
        }

        public List<FamilyInfo> SearchFamiliesByVendor(string searchString,int vendorid)
        {
            return FamilyBLL.SearchFamiliesByVendor(m_curConnCtx, searchString,vendorid);
        }

        public List<ParameterInfo> GetFamilyKeyParameters(Guid familyId)
        {
            return ParameterBLL.GetFamilyKeyParameters(m_curConnCtx, familyId);
        }

        public List<ParameterInfo> GetFamilyParameters(Guid familyId)
        {
            return ParameterBLL.GetFamilyParameters(m_curConnCtx, familyId);
        }

        public ParameterInfo GetFamilyParameterInfo(Guid parameterId)
        {
            return ParameterBLL.GetFamilyParameterInfo(m_curConnCtx, parameterId);
        }

        public List<ParameterValueInfo> GetParamVals(Guid parameterId, List<ParameterValueInfo> paramConstrains)
        {
            return ParameterBLL.GetParamVals(m_curConnCtx, parameterId, paramConstrains);
        }

        public ParameterValueInfo GetParamVal(Guid familyId, Guid instanceId, Guid parameterId)
        {
            return ParameterBLL.GetParamVal(m_curConnCtx, familyId, instanceId, parameterId);
        }

        public System.Data.DataTable GetSubFamilyTable(Guid familyId, List<ParameterValueInfo> paramConstraints)
        {
            return FamilyBLL.GetSubFamilyTable(m_curConnCtx, familyId, paramConstraints);
        }

        public List<ParameterValueInfo> GetDriveParameterVals(Guid familyId, Guid instanceId)
        {
            return ParameterBLL.GetDriveParameterVals(m_curConnCtx, familyId, instanceId);
        }

        public Byte[] GeneratePart(Guid familyId, Guid instanceId, List<ParameterInfo> driveParams, string fileExtension)
        {
            Byte[] retVal = new Byte[0];
            try
            {
                //get the instance path.
                string instancePath = GetInstanceFilePath(familyId, instanceId, ParserOutputType(fileExtension));
                bool bHasCacheFile = false;
                //check whether we have cache
                if (IsFamilyCached(familyId) || System.IO.File.Exists(instancePath))
                {
                    bool bCheckCache = true;
                    //check whether we have custom parameters.
                    foreach (ParameterInfo paramInfo in driveParams)
                    {
                        if (paramInfo.IsCustom)
                        {
                            //check whether the value is equal to family table.
                            ParameterValueInfo pvi = GetParamVal(familyId, instanceId, paramInfo.ID);
                            if (paramInfo.Value != pvi.Value)
                            {
                                bCheckCache = false;
                                break;
                            }
                        }
                    }

                    if (bCheckCache)
                    {
                        //check whether the instance is cached.
                        if (System.IO.File.Exists(instancePath))
                        {
                            bHasCacheFile = true;
                        }
                    }
                }

                //instance if no cache file.
                //
                if (!bHasCacheFile)
                {
                    //no cache, generate it.
                    string templateFile = FamilyBLL.GetTemplateFile(m_curConnCtx, familyId);

                    if (!InvServiceMethod.GeneratePart(templateFile, driveParams, instancePath))
                    {
                        throw new Exception(InvServiceMethod.lastErrMsg);
                    }
                }

                if (System.IO.File.Exists(instancePath))
                {
                    retVal = this.GetBinaryByPath(instancePath);
                }
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }

            return retVal;
        }

        //define events.
        public delegate void StartCachingEventHandler(Object sender, ProgressEventArgs e);
        public event StartCachingEventHandler RaiseStartCachingEvent;

        public delegate void EndCachingEventHandler(Object sender, ProgressEventArgs e);
        public event EndCachingEventHandler RaiseEndCachingEvent;

        public delegate void CacheStepEventHandler(Object sender, ProgressEventArgs e);
        public event CacheStepEventHandler RaiseCacheStepEvent;

        public bool GenerateCache(Guid familyId)
        {
            List<Guid> instances = FamilyTableBLL.GetAllInstances(m_curConnCtx, familyId);

            int cnt = instances.Count;
            int idx = 0;

            if (RaiseStartCachingEvent != null)  RaiseStartCachingEvent(familyId, new ProgressEventArgs(cnt));

            try
            {
                //delete cache.
                DeleteCache(familyId);

                foreach (Guid instanceId in instances)
                {
                    string templateFile = FamilyBLL.GetTemplateFile(m_curConnCtx, familyId);
                    List<string> paths = GetInstanceCachePaths(familyId, instanceId);
                    List<ParameterValueInfo> driveParams = GetDriveParameterVals(familyId, instanceId);
                    List<ParameterInfo> driveParamInfos = new List<ParameterInfo>(driveParams.Count);
                    foreach (ParameterValueInfo item in driveParams)
                    {
                        ParameterInfo driveInfo = GetFamilyParameterInfo(item.ID);
                        driveInfo.Value = item.Value;
                        driveParamInfos.Add(driveInfo);
                    }

                    if (!InvServiceMethod.GenerateCache(templateFile, driveParamInfos, paths))
                    {
                        lastErrMsg = InvServiceMethod.lastErrMsg;
                        return false;
                    }

                    if (RaiseCacheStepEvent != null) RaiseCacheStepEvent(familyId, new ProgressEventArgs(idx++));
                }

                //now, update family cache flag.
                FamilyBLL.UpdateFamilyCachedFlag(m_curConnCtx, familyId, true);
            }

            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
            finally
            {
                if (RaiseEndCachingEvent != null) RaiseEndCachingEvent(familyId, new ProgressEventArgs(cnt));
            }

            return true;
        }

        public bool DeleteCache(Guid familyId)
        {
            string familyCacheFolder = GetFamilyCacheFolder(familyId);

            if (System.IO.Directory.Exists(familyCacheFolder))
            {
                System.IO.Directory.Delete(familyCacheFolder, true);
            }

            //now, update family cache flag.
            FamilyBLL.UpdateFamilyCachedFlag(m_curConnCtx, familyId, false);

            return true;
        }

        public List<ParameterInfo> GetParameters(Byte[] modelData)
        {
            List<ParameterInfo> retList = new List<ParameterInfo>();

            string modelPath = Path.Combine(GetCacheFolder(), "temp.ipt");

            modelPath = SaveBinaryByPath(modelPath, modelData);

            //File.AppendAllText(@"E:\GlobalModules\01_WCFService\11.log", "Path2=" + modelPath);

            if (File.Exists(modelPath))
            {
                retList = InvServiceMethod.GetParameters(modelPath);
            }

            return retList;
        }

        private string GetCacheFolder()
        {
            //string asmPath = System.Reflection.Assembly.GetExecutingAssembly().Location;

            string asmPath = ConfigurationManager.AppSettings["ServerCache"].ToString();

            string asmFolder = System.IO.Path.GetDirectoryName(asmPath);

            string cacheFolder = System.IO.Path.Combine(asmFolder, "ServerCache");

            if (!System.IO.Directory.Exists(cacheFolder))
            {
                System.IO.Directory.CreateDirectory(cacheFolder);
            }
            return cacheFolder;
        }

        private List<string> GetInstanceCachePaths(Guid familyId, Guid instanceId)
        {
            List<string> retPaths = new List<string>();

            string cacheFolder = GetCacheFolder();
            string instanceFolder = System.IO.Path.Combine(cacheFolder, String.Format("{0}\\{1}", familyId, instanceId));

            if (!System.IO.Directory.Exists(instanceFolder))
            {
                System.IO.Directory.CreateDirectory(instanceFolder);
            }
           
 
            string tempPath = System.IO.Path.Combine(instanceFolder, String.Format(@"{0}.ipt", instanceId));
            retPaths.Add(tempPath);
            /*
             tempPath = System.IO.Path.Combine(instanceFolder, String.Format(@"{0}.sat", instanceId));
             retPaths.Add(tempPath);
             tempPath = System.IO.Path.Combine(instanceFolder, String.Format(@"{0}.dwf", instanceId));
             retPaths.Add(tempPath);
             tempPath = System.IO.Path.Combine(instanceFolder, String.Format(@"{0}.igs", instanceId));
             retPaths.Add(tempPath);
             tempPath = System.IO.Path.Combine(instanceFolder, String.Format(@"{0}.stp", instanceId));
             retPaths.Add(tempPath);
             */
            return retPaths;
        }

        private OutputType ParserOutputType(string path)
        {
            string extension = path.ToLower();
            if (extension.EndsWith(@".ipt"))
            {
                return OutputType.kIPT;
            }
            else if (extension.EndsWith(@".igs"))
            {
                return OutputType.kIGS;
            }
            else if (extension.EndsWith(@".sat"))
            {
                return OutputType.kSAT;
            }
            else if (extension.EndsWith(@".dwf"))
            {
                return OutputType.kDWF;
            }
            else if (extension.EndsWith(@".stp"))
            {
                return OutputType.kSTP;
            }

            return OutputType.kIPT;
        }

        private string GetInstanceFilePath(Guid familyId, Guid instanceId, OutputType type)
        {
            string retPath = String.Empty;
            string cacheFolder = GetCacheFolder();
            string instanceFolder = System.IO.Path.Combine(cacheFolder, String.Format("{0}", familyId));
            // string instanceFolder = System.IO.Path.Combine(cacheFolder, String.Format("{0}", familyId, instanceId));
            switch (type)
            {
                case OutputType.kIGS:
                    retPath = System.IO.Path.Combine(instanceFolder, String.Format(@"{0}.igs", instanceId));
                    break;
                case OutputType.kDWF:
                    retPath = System.IO.Path.Combine(instanceFolder, String.Format(@"{0}.dwf", instanceId));
                    break;
                case OutputType.kSAT:
                    retPath = System.IO.Path.Combine(instanceFolder, String.Format(@"{0}.sat", instanceId));
                    break;
                case OutputType.kSTP:
                    retPath = System.IO.Path.Combine(instanceFolder, String.Format(@"{0}.stp", instanceId));
                    break;
                case OutputType.kIPT:
                    retPath = System.IO.Path.Combine(instanceFolder, String.Format(@"{0}.ipt", instanceId));
                    break;
                default:
                    break;
            }

            return retPath;
        }

        private string GetFamilyCacheFolder(Guid familyId)
        {
            string cacheFolder = GetCacheFolder();
            string familyCacheFolder = System.IO.Path.Combine(cacheFolder, String.Format("{0}", familyId));

            return familyCacheFolder;
        }

        private Byte[] GetBinaryByPath(string filePath)
        {
            if (String.IsNullOrEmpty(filePath) || !System.IO.File.Exists(filePath))
            {
                return new Byte[0];
            }

            System.IO.FileStream fs = new System.IO.FileStream(filePath, FileMode.Open, FileAccess.Read);

            Byte[] retBuffer = new Byte[fs.Length];
            fs.Read(retBuffer, 0, (int)(fs.Length));

            return retBuffer;
        }

        private string SaveBinaryByPath(string filePath, byte[] bytes)
        {
            if (bytes.Length == 0)
            {
                return String.Empty;
            }

            //create folder if not exist.
            string folder = System.IO.Path.GetDirectoryName(filePath);
            if (!System.IO.Directory.Exists(folder))
            {
                System.IO.Directory.CreateDirectory(folder);
            }

            System.IO.FileStream fs = new System.IO.FileStream(filePath, FileMode.Create, FileAccess.ReadWrite);
            fs.Write(bytes, 0, (int)(bytes.Length));
            fs.Close();
            return filePath;
        }

        public bool IsFamilyCached(Guid guid)
        {
            FamilyInfo fam = FamilyBLL.GetFamilyInfo(m_curConnCtx, guid);

            return fam.IsCached;
        }


        public int checkUserAuthority(string username)
        {
            List<string> roleList = null;
            try
            {
                roleList = LoginDAL.GetRoleByUserNm(m_curConnCtx, username);
            }
            catch (Exception e)
            {
                
            }

            if (roleList != null && roleList.Contains("Administrators"))
            {
                return 1;
            }

            return 0;

        }

        public bool ValidateUser(string username, string password)
        {
            return Membership.ValidateUser(username, password);
        }
    }
}
